/** @file 
 * @brief Application Programming Interface (API) 
 */

#ifndef __TIROS_H_
#define __TIROS_H_

/* Author: Ratish J. Punnoose, 2006
 * This file is part of TiROS, the Tickless Real-Time Operating System.
 * Copyright(c) 2006, 2007: Ratish J. Punnoose.
 * Copyright(c) 2006 Sandia Corporation. Under the terms of Contract
 * DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
 * certain rights in this software. 
 * 
 * TiROS is free software; you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free
 * Software Foundation; either version 2 or (at your option) any later version.
 *
 * TiROS is distributed in the hope that it will be useful, but WITHOUT ANY
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with TiROS; if not, write to the Free Software Foundation, Inc.,
 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
 *
 * As a special exception, if other files instantiate templates or use macros
 * or inline functions from this file, or you compile this file and link it
 * with other works to produce a work based on this file, this file does not
 * by itself cause the resulting work to be covered by the GNU General Public
 * License. However the source code for this file must still be made available
 * in accordance with section (3) of the GNU General Public License.
 *
 * This exception does not invalidate any other reasons why a work based on
 * this file might be covered by the GNU General Public License.
 *
 */


/**
 * @page config_usage TiROS Configuration
 * <H2> Main Configuration Options </H2>
 * These configuration options can be placed in the proj_config.h file.
 * <DL>
 *    <DT> TIROS_MAX_ISR_NESTING [1]:<DD>  Define the maximum
 *    nesting level for ISRs.   TiROS supports nested
 *    interrupts.  By default, TIROS_MAX_ISR_NESTING is set to 1. This
 *    specifies that only one ISR will run at a time (interrupts should
 *    not be enabled within ISRs.)   TiROS cannot enforce this, so the
 *    user should ensure that interrupts are not reenabled within an
 *    ISR beyond this defined level. \sa isr.
 *    <DT> TIROS_MAX_PROCS: <DD> (Integer value) The maximum number of tasks.
 *    This should also include the idle task.
 *    <DT> TIROS_ENABLE_MUTEX [1 | 0] : <DD> By default mutexes are
 *    enabled.  If they should be disabled, then define
 *    TIROS_ENABLE_MUTEX to be 0 in the proj_config.h file.
 *    <DT> TIROS_MAX_MUTEXES [255]: <DD> Maximum number or mutexes
 *    that can be held by a single task.  This can be overridden by
 *    defining TIROS_MAX_MUTEXES in proj_config.h
 *    <DT> TIROS_ALLOW_SLEEP_W_MUTEX [0 | 1] : <DD>By default TiROS does
 *    not allow tasks that are holding a mutex to sleep. An error code
 *    is returned.  This is done to prevent unbounded locking.  This
 *    behaviour can be overridden by defining this directive to 1 in
 *    the user's configuration file.
 *    <DT> TIROS_PRIO_INHERIT_PROTOCOL: <DD> (Deprecated). (Previous Usage:Define this in the user configuration
 * file, if priority inheritance will be used.  By default, priority
 * ceiling will be used). <BR> 
 *         This option is no longer used.  Priority Ceiling is always
 *         used. It is better.
 *    <DT> TIROS_ENABLE_CSEM [1 | 0] : <DD> By default counting semaphores are
 *    enabled.  If they should be disabled, then define
 *    TIROS_ENABLE_CSEM to be 0 in the proj_config.h file.
 *    <DT> TIROS_ENABLE_MSGQ [1 | 0] : <DD> By default message queues are
 *    enabled.  If they should be disabled, then define
 *    TIROS_ENABLE_MSGQ to be 0 in the proj_config.h file.
 *    <DT> TIROS_ENABLE_EFLAG [1 | 0] : <DD> By default event flags are
 *    enabled.  If they should be disabled, then define
 *    TIROS_ENABLE_EFLAG to be 0 in the proj_config.h file.
 *    <DT> TIROS_USER_CTXT_UPCALL: <DD> This can be used to perform user defined
 *    functions when tasks are switched.  This  is an upcall made by
 *    the scheduler upon task switch.  If this is defined, the
 *    user_ctxt_upcall function defined in the API MUST be implemented by
 *    the user.   This feature can be used in imaginative
 *    ways to set task-specific settings.  For example, a user can
 *    implement per task power control. \sa os_advanced.
 *    <DT> TIROS_DEBUG_LEVEL 0-4 [0]: <DD> Debugging messages can be
 *    output from TiROS by setting TIROS_DEBUG_LEVEL.
 *    \verbatim
      0 - No debugging messages.
      1 - Critical error messages.
      2 - Adds warning mesages.
      3 - Adds informational messages.
      4 - Adds trace messages.
      \endverbatim
      The debugging messages are output by calling the putchar()
      function.  This function may be adapted by the user to direct
      the output to a serial port, or to a file depending on the
      hardware platform. \sa os_advanced.
 *    <DT> TIROSINT_DATA_DEBUG : <DD> If this is defined, the
 *    functions to access internal TiROS data structures is enabled.
 *    This is useful for debugging.  \sa os_advanced.
 *    <DT> TIROS_STK_CHECK : <DD> If this is defined, TiROS keeps
 *    track of additional information that can be used for getting
 *    useful information about stack usage.  \sa os_advanced.
 *    <DT> TIROS_C90_COMPATIBLE [0 | 1]: <DD> Use code downward compatible with an
 *    ISO C90 standard compiler. The code of concern is the definition
 *    of the message queue structure.  Some older compilers or strict
 *    C++ compilers don't support zero-length array/flexible
 *    arrays/variable-length array/.  These are useful as the last
 *    element of a structure which is really a header for a variable
 *    length object.  TiROS uses such a construct to save memory when
 *    initializing message queues. 
 *    The default behaviour is to work with GCC or
 *    any ISO C99 standard compiler.  If your compiler complains that
 *    struct msgQ or msgQ_t has incomplete type or that the sizeof
 *    operator cannot be applied to this struct, then define this to
 *    be 1 in your proj_config.h file. 
 *
 *    <DT> TiROS Data Type configuration: <DD>  Some of the data types used within
 *        TiROS data structures can be modified by the user.
 *        Normally, this is not necessary.  In special cases, the user
 *    may want to override the defaults.  For example, by default, the
 *    counting semaphores use an 8 bit integer (signed) to represent
 *    count. This limits the maximum count to 127.  The user can
 *    override this default and force TiROS to use a 16 bit integer for
 *    the count.  This vastly increases the count range.  For a
 *    comprehensive list of these options, see tr_types.h.
 *
 *   <DT> Other options: <DD> There can be other hardware port specific configuration
 * options.  For a description of this, look in the tr_port.h file in the
 * appropriate port directory.   
 * </DL>
 *
 * @page os_api Application Programming Interface (API)
 * <H2> The Application Programming Interface (API) is described in
 *     the following major sections.</H2>
 * <OL>
 *   <LI> \ref crit_secs.
 *   <LI> \ref isr.
 *   <LI> \ref os_initialization.
 *   <LI> \ref os_task.
 *   <LI> \ref os_time.
 *   <LI> \ref os_time_utils.
 *   <LI> \subpage os_sync.
 *   <LI> \ref os_advanced.
 * </OL>
 */




#include <tiros/tr_types.h>




/** @defgroup func_options  Function Options
 * These option flags can be used with the various API functions.
 * @{ */

/** Do not block while performing this command. */
#define O_NONBLOCKING		0x01

/** Use effective priority instead of real priority for this
    command. */
#define O_EFFECTIVE_PRIO	0x01

/** Use relative time instead of absolute time */
#define O_RELATIVE_TIME		0x02



/** Clear an event flag instead of setting it.
 * This is only used while setting an event flag. */
#define O_EFLAG_CLEAR		0x04

/** Trigger an event flag, rather than permanently setting it 
 * This is only used while setting an event flag. */
#define O_EFLAG_TRIGGER		0x08

/**  Wait for all the events corresponding to requested bits.
 * Only applicable to event flags. */
#define O_EFLAG_AND		0x04

/** Wait for any of the events correspoind to the requested bits. */
#define O_EFLAG_OR		0x00


/** @} */



/** @defgroup crit_secs Critical Sections
 * 
 * Critical Sections can be used to prevent preemption.
 * Within a
 * critical section, a task will not be interrupted. The following
 * code structure is used to implement critical sections:
 * 
 Eg.
 *\code
 * unsigned char port_status;  // This is global, may be accessed
 *                             // through an interrupt and its
 *                             // access must be protected with
 *                             // critical sections
 *
 * void tst(void) {
 *  int a;
 *  char x;
 *  char txt[20];
 *  OS_CRITICAL_ENABLE();  // This should be declared immediately after
 *                        // other variable declarations.
 *
 *  tst[0] = 3;
 *
 *  OS_CRITICAL_BEGIN();      // Protect port_status using critical
 *  if (port_status) {        // sections 
 *      x = port_status;
 *      port_status = 0;
 *  }
 *  OS_CRITICAL_END();
 * }
 * \endcode
 * @{ */

/** Enable a critical section within a function. 
 * This must be the first call in the functions after the variable
 * declarations. This has to be called before  OS_BEGIN_CRITICAL() or
 *  OS_CRITICAL_END() can be called.  See example for critical sections. */
#define OS_CRITICAL_ENABLE()     OS_PORT_CRITICAL_ENABLE()

/** Begin a critical section.
 *  
 *  This should always be matched with an
 *   OS_CRITICAL_END() in the same function. Critical sections should be
 *  enabled in the function using  OS_CRITICAL_ENABLE() */
#define OS_CRITICAL_BEGIN()      OS_PORT_CRITICAL_BEGIN()

/** End a critical section.
 * This should be matched to a corresponding \ref OS_BEGIN_CRITICAL() call. */
#define OS_CRITICAL_END()        OS_PORT_CRITICAL_END()

/** Explicitly enable interrupts.
 * Ideally, there should be no need to use this call.  The
 * OS_CRITICAL_BEGIN() and  OS_CRITICAL_END() calls are much safer,
 * since they will store the interrupt state at the beginning of a
 * critical section and restore the state at the end of a critical
 * section.  There might be rare occassions where this call may be
 * needed (for example to explicitly re-enable interrupts within an
 * ISR) */
#define OS_INT_ENABLE()          OS_PORT_INT_ENABLE()


/** Explicitly disable interrupts.
 * Ideally, there should be no need to use this call.  The
 *  OS_CRITICAL_BEGIN() and  OS_CRITICAL_END() calls are much safer,
 * since they will store the interrupt state at the beginning of a
 * critical section and restore the state at the end of a critical
 * section.  There might be rare occassions where this call may be
 * needed to explicitly disable interrupts. */
#define OS_INT_DISABLE()          OS_PORT_INT_DISABLE()


/** @}  End Critical Sections. */



/** @defgroup isr Usage with Interrupt Service Routines
 * TiROS API calls can be used within ISRs.
 * Mark the beginning and end of an ISR, so that TiROS can
 * appropriately perform task scheduling if needed.  
 * Interrupt service routines are notoriusly hardware and compiler
 * dependent, so use the instructions for your  hardware/compiler
 * port.
 *
 * TiROS supports three ways of servicing interrupts:
 * <OL>
 *  <LI> Simple Usage:  An ISR can be written as
 * you would normally write one for your hardware only if all of the
 * following are true:
 *  <UL> 
 *        <LI> Interrupts will stay disabled while the ISR is being
 * invoked.
 *        <LI> The ISR will not call any TiROS api calls.
 *        <LI> The ISR will not perform any action that will cause any
 * task to become unblocked, or in general, will not change the state
 * of any task.
 * </UL> 
 *  <LI> Saving context per interrupt response: This is the standard
 * way to service interrupts. Due to the presence of an OS, the
 * sequence of steps to be taken are as follows:
 * \code
 *     function ISR( ) {
 *        stkptr = save_context_of_task();  // See port instructions.
 *         // stkptr = pointer to stack of saved task.
 *         
 *         perform_functions();
 *        newstkptr = osint_taskswitcher(stkptr);
 *        load_context_of_newtask(newstkptr);    
 *     }
 * \endcode
 * The exact implementation depends on the hardware port. See the port
 *        documentation for more details.
 *        
 *       
 * <LI> Using Kernel Traps: TiROS can take advantage of  hardware
 *        architectures that can support a software initiated
 *        interrupt (kernel trap).  This is the most preferable
 *        option because interrupt service routines have very low
 *        overhead and can yet use all of the TiROS calls and interact
 *        with tasks.  If your port supports this, use this.  It also
 *        makes writing the ISRs very simple. The way this works is
 *        that the context of a task is not saved on entry to the
 *        ISR. Instead, at the end of the ISR,  OS_ISR_END() determines
 *        if the task has to be switched out. If so, it invokes a
 *        kernel trap.  The kernel trap is entered as soon as the ISR
 *        ends. The kernel trap performs the context switch. 
 *        Thus, the context switch overhead is only invoked when
 *        necessary, not at every ISR.
 * Eg. 
 * \code
 * void ISR_function(void) 
 * {
 *   int x;
 *   OS_CRITICAL_ENABLE();   // Only needed if any critical sections
 *                           // will be used and interrupt nesting is enabled.
 *
 *   OS_ISR_BEGIN();         // Mark the beginning of an ISR. Note
 *                           // that if OS_CRITICAL_ENABLE() is also
 *                           // present, then this comes after 
 *                           // that. 
 *  
 *  x = 3;
 *    Do more stuff ....
 *  
 *  OS_ISR_END();
 * }
 * \endcode
 * 
 * </OL>
 * TiROS supports nested interrupts.  However, for reliability, try
 * not to use nested interrupts unless absolutely necessary.
 * Interrupt service routines use the stack of the task that was
 * running when the interrupt occured.  Nested interrupts can cause
 * the stack to grow unpredictably and overflow.
 * 
 * To use nested interrupts, write code as below:
 * \code
 * extern uint8_t os_isr_nesting; // Internal TiROS variable that keeps track
 *                                // of nesting level.
 * void ISR_function(void) 
 * {
 *   int x;
 *   OS_CRITICAL_ENABLE();   // Only needed if any critical sections
 *                           // will be used and interrupt nesting is enabled.
 *
 *   OS_ISR_BEGIN();         // Mark the beginning of an ISR. Note
 *                           // that if OS_CRITICAL_ENABLE() is also
 *                           // present, then this comes after 
 *                           // that. 
 *
 *  if (os_isr_nesting < TIROS_MAX_ISR_NESTING) {
 *     // Interrupts should only be reenabled if the current nesting level
 *     // is less than or equal to the maximum configured nesting level.
 *     renable_interrupts();
 *  }
 *  x = 3;
 *    Do more stuff ....
 *  
 *  OS_ISR_END();
 * }
 * \endcode
 *
 * @{ */



/** Enable this within ISRs immediately after any variable
 *  declarations, and after any OS_CRITICAL_ENABLE(). */
#define OS_ISR_BEGIN()           OS_PORT_ISR_BEGIN()

/** Mark the end of an ISR. 
 *  This should be called at the end of an ISR.  There must exist a
 *  corresponding OS_ISR_BEGIN() statement.
*/
void OS_ISR_END(void);
/** @} */







/** @defgroup os_initialization OS initialization and running
 * Routines to initialize and start the OS.
 * @{ */

/** Initialize the OS.
 * This initializes the OS data structures.  This should be the first
 * OS API called. */
void os_init(void);

/** Start the OS by running tasks in the ready list.
 * Note: Tasks should have been created and made ready to run before
 * this function is called. */
void os_start(void);
/** @} */









/** @defgroup os_task Task creation and management
 * This group of functions provides routines to create, delete, and
 * manipulate the state of tasks.
 * @{ */

/** Minimum amount of space is oswwords (not bytes) */
#define TIROS_MIN_CTXT_SZ      TRPORT_MIN_CTXT_SZ

/** Task Prototype.
 *  This specifies the form of the function that begins a task.  
 */
typedef  void (* taskfunc_t)(void  * function_argument);



/** Create a task.
 *
 * Calling Context: 
 *  -# Before os_start().
 *  -# From within a task.
 *  -# From an ISR.
 *
 * \code
  #define TASK1_STKSZ  (TIROS_MIN_CTXT_SZ  + 64)  // 64 words more than min
  osword_t task1_stk[TASK1_STKSZ]; 
  void task1(void *arg)
  {
  //  Task does something. never exits 
  }
  
  void main(void)
  {
    tid_t t1_tid;
    tid_t idle_tid; 
    int arg_to_pass_to_task1
    os_init();
    t1_tid = os_task_create(task1, (osptr_t) arg_to_pass_to_task1,
                            task1_stk, TASK1_STKSZ, TASK1_PRIO);
   
    if (t1_tid == ILLEGAL_ELEM) {
      error("task1 error");
    }  
              .
              .
              .
              

    os_start();     
  }
 * \endcode
 * @param func  Function pointer to the task.
 * @param param The parameter to be passed to the task.
 * @param stack Pointer to the stack to be used.
 * @param stacksize  Size of the stack. NOTE: This is specified in
 *                 osword_t not in bytes.  This is so that the stack
 *                 is not misaligned.  Use the TIROS_MIN_CTXT_SZ value
 *                 to help in sizing the stack appropriately.
 * @param priority  Task priority.
 * @return ID of the task created or ILLEGAL_ELEM if call failed. This
           happens if there are no TCBs or if a task is already
           allocated to the priority level. */
tid_t os_task_create(taskfunc_t func, /*@shared@*/ osptr_t param, 
		     /*@shared@*/ osword_t *stack, osword_t stacksize, 
		     tid_t priority);


/** A task's self identification
 *
 * Calling Context: 
 *  -# Before os_start().
 *  -# From within a task.
 *  -# From an ISR.
 *
 * @return  Return the task id or ILLEGAL_ELEM if called from an ISR
 * or before os_start().  */
tid_t os_self_tid(void);


/** Set the priority of a task.
 * This modifies the base priority of a task.
 * The function returns \ref SUCCESS if the priority change was successful
 * OR if the current priority of the task is the same as the desired
 * priority.
 * When the default priority ceiling algorithm is used for mutual
 * exclusion,  the priority of a task holding a mutex cannot be
 * changed.  Attempting this returns \ref ERR_WOULDBLOCK_MUTEX
 *
 * Calling Context: 
 *  -# Before os_start().
 *  -# From within a task.
 *  -# From an ISR.
 *
 * @param task  ID of the task to have a priority change.
 * @param prio  New priority.
 * @return {\ref SUCCESS,         
 *          \ref ERR_NOSUCHTASK, 
 *          \ref ERR_PRIO_IN_USE, 
 *          \ref ERR_WOULDBLOCK_MUTEX    }. */
int8_t os_prio_set(tid_t task, tid_t prio);



/** Get the priority of a task.
 * @param task  ID of the task whose priority is queried.
 * @param options Get either the real or effective priority.  If
 * \ref O_EFFECTIVE_PRIO is specified, then the effective priority is
 * returned. 
 *
 * Calling Context: 
 *  -# Before os_start().
 *  -# From within a task.
 *  -# From an ISR.
 *
 * @param task ID of the task
 * @param options [ \ref O_EFFECTIVE_PRIO ]
 * @return ILLEGAL_ELEM if failed or the task priority */ 
tid_t os_prio_get(tid_t task, uint8_t options);

/** Delete a task.
 * A task can be deleted if it is not in possession of any mutexes.
 * A task can also delete itself.
 *
 * Calling Context: 
 *  -# Before os_start().
 *  -# From within a task.
 *  -# From an ISR.
 *
 * @param task  Task to be deleted.  This can be the current task.
 * @return  {\ref SUCCESS, 
 *           \ref ERR_NOSUCHTASK, 
 *           \ref ERR_TASKBLOCKED}. */
int8_t os_task_del(tid_t task);

/** Suspend a task.
 *  A task can only be suspended if it is not holding any mutexes.
 *   This is by design: If a task holding a mutex were to be
 *  suspended, it could result in a priority inversion or starvation.  
 *  A task can also suspend itself. In this case, it will only resume
 *  running after some other task resumes it (\sa os_task_resume).
 *  When the task resumes, it returns \ref SUCCESS (not
 *  \ref ERR_RESUMED), since this is the intended operation.
 *
 * Calling Context: 
 *  -# Before os_start().
 *  -# From within a task.
 *  -# From an ISR.
 *
 * @param task  Task to be suspended. 
 * @return  {\ref SUCCESS, 
 *           \ref ERR_NOSUCHTASK, 
 *           \ref ERR_TASKBLOCKED} . */
int8_t os_task_suspend(tid_t task);

/** Resume a task.
 *
 * This call can be used to forcibly resume: 1) a task that is waiting
 * on a lock,  2) one that has been suspended, 3) one that is
 * sleeping.
 * The effect of this call is to make the designated task ready for
 * running. 
 * Note: a task that is  sleeping may be woken up earlier than its sleeptime, explicitly by
 * the resume command.  Similarly, a task that is waiting on a lock will be
 * forcibly readied and scheduled even before its timeout expires.
 * If a task is already in the ready queue, then it is not altered.
 *
 * Calling Context: 
 *  -# Before os_start().
 *  -# From within a task.
 *  -# From an ISR.
 *
 * @param task  Task to be resumed.
 * @return  {\ref SUCCESS, 
 *           \ref ERR_NOSUCHTASK }.  */
int8_t os_task_resume(tid_t task);
/** @} */






/** @defgroup os_time  Time services provided by the OS 
 * This set of API calls allows time related functions.
 * TiROS operates with high-resolution time.  Sleep and timeouts are
 * specified in absolute or  relative time (using the \ref
 * O_RELATIVE_TIME option).  Time is represented using the 
 * \ref  trtime_t structure.  This structure consists of two elements:
 *  <OL>
 * <LI> A subsecond unit (could be milli-seconds, nano-seconds,etc.) </LI>
 * <LI> A supersecond unit ( could be a unit of 1 second, 10 secs, 1
 *    minute etc. </LI>
 * </OL>
 * This choice of time is kept deliberately vague, since the
 * application is an embedded system, where these functions have to be
 * fast, take advantage of the hardware, and cannot waste cycles
 * converting time units from the hardware representation to a
 * standard form.  The actual representation of the time structure is
 * specified by the platform specific port.
 * @{ */

/** Get the current time.
 *
 * Calling Context: 
 *  -# Before os_start().  (The value may not be correct)
 *  -# From within a task.
 *  -# From an ISR.
 *
 * @param [out] curr_time Pointer to structure where the time should
 * be  stored. 
 */
void os_time_get(/*@out@*/ trtime_t *curr_time);


/** Set the current time.
 * This sets the current time.  This has to be used with care.
 * This can affect tasks that have been sleeping or waiting for a lock.
 * Such tasks will be woken up if the new time set is beyond their
 * wakeup deadline.
 * This system call may not be possible on some hardware ports.
 *
 * 
 * Calling Context: 
 *  -# Before os_start().
 *  -# From within a task.
 *  -# From an ISR.
 *
 * To set the time before the os has started use the hal_time_set
 * function directly, which is supplied by the hardware port.
 *
 * @param new_time  Pointer to structure with the new time.
 * @return {\ref SUCCESS,
 *          \ref ERR_FAILED}
 */
int8_t os_time_set(trtime_t const *new_time);

/** Wake the invoking task at a specific time.
 * The task can be woken up earlier by an explicit resume.
 * The task is not allowed to sleep if it holds a mutex lock.
 * This call is not allowed from an ISR.
 *
 * Calling Context: 
 *  -# From within a task.
 *  -# Call before os_start() will result in an error.
 *  -# Call from ISR will result in an error.
 *
 * @param [in] wake_time  Time at which to be woken up.
 * @param  options Default is absolute time. For relative time, set
 *  \ref O_RELATIVE_TIME. 
 * @return {\ref SUCCESS, 
 *          \ref ERR_RESUMED, 
 *          \ref ERR_WOULDBLOCK_MUTEX, 
 *          \ref ERR_WOULDBLOCK_ISR} */
int8_t os_wake_at(trtime_t const *wake_time, uint8_t options);
/** @} */






/** @page os_sync Task cooperation and synchronization primitives
 * TiROS synchronization mechanisms include mutexes, counting
 * semaphores, message queues, and event flags.  For all of these,
 * TiROS supports blocking and non-blocking operation and timeouts. 
 * In all cases, the highest priority task that is waiting on any of
 * these synchronization primitives has first access.
 *<OL>
 *<LI> \ref os_mutex.
 *<LI> \ref os_csem.
 *<LI> \ref os_msgq.
 *<LI> \ref os_eflag.
 *</OL>
 */

#if (TIROS_ENABLE_MUTEX == 1)
/** @defgroup os_mutex Mutexes
 * This page contains the API for mutex management.   Mutexes are used
 * to synchronize access by cooperating tasks to shared
 * resources.  For every shared resource, create an associated shared
 * mutex.  Mutexes should be locked by a task before beginning usage
 * of the shared resource and then unlocked after the usage is over.
 * A task cannot lock a mutex that is already locked by another
 * mutex.  It will either block for the mutex to unlock or will return
 * an error code (depending on the options used).  Mutexes must always
 * be used in a lock/unlock sequence.
 * \code
 * mutex_t resource_mutex; // Previously initialized (possibly in main)
 * void task1(void *dummy)
 * {
 *     while(1) {
 *       mutex_lock(&resource_mutex, 0, 0);
 *       do_stuff();
 *       mutex_unlock(&resource_mutex);
 *       do_other_stuff();
 *     }
 * }
 * \endcode
 * 
 * A detailed description of the design and implementation of
 * mutexes within TiROS are provided in the
 * \ref mutex_properties section. 
 *
 * NOTE: Always initialize before use.  Never initializae a mutex that
 * is in use.
 * @{ */

/** Initialize mutex.
 *
 * Calling Context: 
 *  -# Before os_start().
 *  -# From within a task.
 *  -# From an ISR.
 * 
 * @param m  Pointer to mutex structure
 * @param prio_ceiling  The priority ceiling, if the priority celing
 * protocol is used.  If priority inheritance is used, then the
 * prio_ceiling should be set to ILLEGAL_ELEM.
 * The prio_ceiling MUST be unique (no task should have this as its
 * base priority).
 */
void mutex_init(/*@notnull@*/ /*@shared@*/ mutex_t *m, tid_t prio_ceiling);

/** Get mutex owner
 * This returns the task id of the owner of a specified mutex.  This
 * is an instantaneous snapshot of the state of the mutex. 
 * Due to preemption, the owner may have changed by the time the
 * callee acts on this information.
 * Example:
 * \code
 *    tid_t tmp;
 *    tmp = mutex_owner( m);  // M has been initialized previously 
 *    do_other_stuff();
 *    if (tmp == other_task)  
 *        do_more_stuff();    // the owner of m may have changed.
 * \endcode
 * Use critical sections to prevent a block of code from being
 * executed uninterrupted.
 * NOTE: The mutex must be intialized before this call, else the
 * return value is meaningless.
 *
 * Calling Context: 
 *  -# After mutex_init() of m (There is no check to ensure this). AND
 *    -# Before os_start().
 *    -# From within a task.
 *    -# From an ISR.
 *
 * @return The id of the mutex owner or ILLEGAL_ELEM if it is unlocked.
 */ 
tid_t mutex_owner(/*@notnull@*/ /*@shared@*/ mutex_t const *m);

/** Lock mutex.
 * This is used to exclusively lock a mutex by a task.  The locking
 * behavior depends on the mutex protocol that has been configured.
 * If the specified mutex is not locked, it is locked by the calling
 * task at the end of the call, and a SUCCESS is returned.  Attempts
 * by a task to lock a mutex that it already holds also return
 * SUCCESS.  If a task recursively locks a mutex multiple times,
 * it must also recursively unlock it the same number of times.
 *
 *  Attempts by an ISR to lock a mutex will result in an
 * error code of ERR_LOCK_ISR, since ISRs are not allowed to lock
 * mutexes. If a task already has locked TIROS_MAX_MUTEXES mutexes,
 * then ERR_FULL will be returned, as it is not allowed to lock any
 * more mutexes.
 * Attempts to lock a mutex owned by a different task will
 * result in blocking.  If the O_NONBLOCKING option is specified, then
 * the ERR_WOULDBLOCK error code is returned, else the task is made to
 * wait until the timeout, when ERR_TIMEOUT is returned.  If the
 * task is explicitly resumed during its wait, it receives the
 * ERR_RESUMED code.  
 *
 *
 * Calling Context: 
 *  -# After mutex_init() of m (There is no check to ensure this). AND
 *    -# From within a task.
 *    -# Call before os_start() will result in an error.
 *    -# Call from ISR will error.
 *
 * @param m Pointer to mutex
 * @param timeout   Timeout. This can be 0 for infinite timeout.
 * @param options   Combination of [\ref O_RELATIVE_TIME | \ref O_NONBLOCKING].
 * @return {\ref SUCCESS , 
 *          \ref ERR_LOCK_ISR, 
 *          \ref ERR_LOCK_PRIO_CEIL,
 *          \ref ERR_WOULDBLOCK, 
 *          \ref ERR_TIMEOUT, 
 *          \ref ERR_RESUMED, 
 *          \ref ERR_FULL}.
 */
int8_t mutex_lock(/*@notnull@*/ /*@shared@*/ mutex_t *m,
		  trtime_t const *timeout, 
		  uint8_t  options);

/** Unlock Mutex.
 *
 * Calling Context: 
 *  -# After mutex_init() of m (There is no check to ensure this). AND
 *    -# From within a task.  Must be owner to succeed.
 *    -# Call before os_start() will result in an error.
 *    -# Call from ISR will error.
 *
 * @param m Pointer to mutex.
 * @return {\ref SUCCESS, 
 *          \ref ERR_NOTOWNER} */
int8_t mutex_unlock(/*@notnull@*/ /*@shared@*/ mutex_t *m);
/** @} */
#endif /* TIROS_ENABLE_MUTEX */







#if (TIROS_ENABLE_CSEM == 1)
/** @defgroup os_csem Counting semaphores
 * Counting semaphores can be used to keep a shared count by different
 * tasks. They have a value between 0 to a specified MAX value.
 *
 * The P() operation (Prolaag) decreases the count of the counting
 * semaphore. If the count is zero, the task blocks since it cannot be
 * decreased further.  The V() operation (Verhoog) increments the
 * count of the counting semaphore.  This operation is non-blocking.
 *
 * Counting semaphores are useful for event notifications.  For
 * example, a message server task can perform a P() operation on a message
 * counting semaphore.  When a message has to be sent to the message
 * server, a message client task performs a V() operation on the same
 * semaphore. This unblocks the message server.  If multiple client
 * tasks send messages, the message server has a count of the number
 * of times the message counter has been V()ed.
 *  
 * If multiple servers are blocked on a counting semaphore, the
 * highest priority blocked server is alerted when the semaphore is
 * incremented. 
 *
 * NOTE: A custom type csemval_t is used for the semaphore count.  This is of
 * type signed integer.  By default, it is an 8-bit integer (max val
 * of 127).  This can be overridden (see tr_types.h).
 *
 * NOTE: Always initialize before use.
 *
 * \code
 * csem_t cs; // Previously initialized (possibly in main)
 * void task1(void *dummy)
 * {
 *     while(1) {
 *       csem_P(&cs, 0, 0);  // Wait for semaphore
 *       do_stuff();
 *     }
 * }
 * void task2(void *dummy)
 * {
 *     while(1) {
 *       do_stuff();
 *       do_other_stuff();
 *       // Release task1 
 *       csem_V(&cs);       // Release semaphore
 *       do_stuff();
 *     }
 * }
 *
 *
 * \endcode

 * @{ */

/** Initialize counting semaphore.
 *
 * Calling Context: 
 *  -# Before os_start().
 *  -# From within a task.
 *  -# From an ISR.
 *
 * @param cs  Pointer to counting semaphore
 * @param init_val  Initial value 
 * @param max_val   Maximum value for the counting semaphore. The
 * semaphore cannot be incremented past this number.   */
void csem_init(/*@notnull@*/ /*@shared@*/ csem_t *cs, csemval_t init_val, csemval_t max_val);

/** Obtain the value of a counting semaphore
 * 
 * Calling Context: 
 *  -# After csem_init() of cs (There is no check to ensure this). AND
 *    -# Before os_start().
 *    -# From within a task.
 *    -# From an ISR.
 *
 * NOTE: the counting semaphore must previously have been initialized
 * for this to have any meaningful return value.
 * @param cs Pointer to counting semaphore
 * @return The value of the semaaphore */
csemval_t csem_count(/*@notnull@*/ csem_t const *cs);

/** Decrease (prolaag) the value of a counting semaphore.
 *
 *  This decreases the value of a counting semaphore.  If the value is
 * zero, the caller blocks until another task increments the
 * semaphore OR until the timeout duration OR until another task
 * explicitly resumes (\sa os_task_resume) this task.
 * The caller can prevent blocking by using the O_NONBLOCKING option.
 * On success, the value returned is the value of the semaphore
 * immediately after the decrease.
 *
 * Calling Context: 
 *  -# After csem_init() of cs (There is no check to ensure this). AND
 *    -# From within a task.
 *    -# Before os_start() (error if blocking needed).
 *    -# From an ISR (error if blocking needed).
 *
 * @param cs Pointer to counting semaphore
 * @param timeout  Timeout.  This can be 0, for infinite timeout.
 * @param options   [\ref O_RELATIVE_TIME | \ref O_NONBLOCKING]
 * @return {Semaphore count if successful,  
 *          \ref ERR_WOULDBLOCK_ISR,
 *          \ref ERR_WOULDBLOCK_MUTEX, 
 *          \ref ERR_TIMEOUT, 
 *          \ref ERR_RESUMED } */
csemval_t csem_P(/*@notnull@*/ /*@shared@*/ csem_t *cs, trtime_t const *timeout, uint8_t options);

/** Increase (verhoog) the value of a counting semaphore.
 * This is a non-blocking function.  If the maximum value of the
 * semaphore is reached, an ERR_FULL message is returned.
 *
 * NOTE: On success, the value returned is the value of the semaphore 
 * immediately after the increase.  If there are other tasks waiting
 * to csem_P on the counting semaphore, the value returned is that
 * before these other tasks have completed the csem_P operation.
 * Example:
 * \code
 * csemval_t tmp;
 * // Current state of counting semaphore cs is 0.  There are two
 * // tasks blocked doing a csem_P on it.
 * tmp = csem_V(&cs);  // Value of tmp is 1, because of the csem_V
 * 
 * tmp = csem_count(&cs); // Value of tmp is 0, because one of the tasks that
 *                        // that was blocked on csem_P(&cs) has
 *                        // completed the prolaag and now the value
 *                        // of cs is back to zero.
 * \endcode
 *
 * Calling Context: 
 *  -# After csem_init() of cs (There is no check to ensure this). AND
 *    -# From within a task.
 *    -# Before os_start().
 *    -# From an ISR.
 *
 * @param cs Pointer to counting semaphore
 * @return {Semaphore count or \ref ERR_FULL} */
csemval_t csem_V(/*@notnull@*/ /*@shared@*/ csem_t *cs);
/** @} */
#endif /* TIROS_ENABLE_CSEM */







#if (TIROS_ENABLE_MSGQ == 1)
/** @defgroup os_msgq Message Queues
 * Message Queues can be used to send arbitrary messages between
 * tasks.  Messages are sent in the form of generic pointers to
 * memory.  TiROS handles these message pointers in an opaque manner
 * and does not care what they point to.
 * It is important to note that the maximum size of the message queue
 * has to be known when the message queue is intialized.  It cannot be
 * resized on the fly.  A message server can wait on a message queue
 * or poll it (with the O_NONBLOCKING option).  A message client can
 * send a message on the queue which will unblock any waiting server.
 * If multiple tasks are waiting on the same message queue, the
 * one with the highest priority will be unblocked first.
 *
 * NOTE: A custom type mqind_t is used for the queue length.  This is of
 * type unsigned integer.  By default, it is an 8-bit integer (max val
 * of 255).  This can be overridden (see tr_types.h).
 *
 * NOTE: Always initialize before use.
 *
 * \code
 * #define TST_QSZ 4
 * osword_t tst_Q[msgQ_MEMSZ(TST_QSZ)];   // Previously initialized
 * void task1(void *dummy)
 * {
 *   int8_t rc;
 *   osptr_t rx_val;
 *   while(1) {
 *       rc = msgQ_recv( (msgQ_t*)tst_Q, 0, 0, &rx_val);
 *       if (rc == SUCCESS) {
 *          do_something(rx_val);
 *       }
 *   }
 * }
 * void task2(void *dummy)
 * {
 *   int8_t rc;
 *   while(1) {
 *       rc = msgQ_send( (msgQ_t*)tst_Q, 7); // Send 7 to task1
 *   }
 * }
 *
 * \endcode
 * @{ */

/** Get the memory size for a message queue
 * This macro makes sure that the memory is word aligned.
 * @param qlen Length of the message queue
 * @return Memory occupied (in words) */
#define msgQ_MEMSZ(qlen)  ((sizeof(struct msgQ) +  \
			    (mqind_t)(qlen) * sizeof(osptr_t) +		\
			    sizeof(osword_t)-1) / 	sizeof(osword_t)) 

/** Simple cast from memory to msgQ pointer
 * @param msgq_mem Array of type osword_t that is to be cast to
 *        a msgQ pointer 
 * @return Pointer to msgQ (which points to the same memory as msgq_mem */
static inline msgQ_t* msgQ_mem2ptr(osword_t *msgq_mem)
{
	/*lint -e{740} The following casting is OK */	
	return (msgQ_t*)msgq_mem;
}

/** Initialize a message queue.
 *
 * Calling Context: 
 *  -# Before os_start().
 *  -# From within a task.
 *  -# From an ISR.
 *
 * @param m  Pointer to message queue
 * @param qlen  Length of the queue.
 *  NOTE: The queue memory is contained in the msgQ structure.
 *  It is EXTREMELY IMPORTANT that the qlen argument to this call be
 *  less than or equal to the length of the message queue that was
 *  used as an argument for msgQ_MEMSZ( ). Failing to follow this rule
 *  will result in buffer overflows.
 *
 * Eg.:  
 * \code
 *   msgQ_t *m;
 *   qlen = 10;
 *
 *   osword_t dummy[ msgQ_MEMSZ(qlen)];
 *   m = msgQ_mem2ptr(dummy);
 *   msgQ_init(m, qlen);
 * \endcode
 * The memory should not be transient.  It should be global, or
 * allocated on the heap. 
*/
void msgQ_init(/*@notnull@*/ /*@shared@*/ msgQ_t * m, mqind_t qlen);
/*lint -ecall(740,msgQ_init) If dummy is passed directly to msgQ_init
 *   with casting, this is OK. */

/** The number of messages in the queue.
 *
 * Calling Context: 
 *  -# After msgQ_init() of m (There is no check to ensure this). AND
 *    -# Before os_start().
 *    -# From within a task.
 *    -# From an ISR.
 *
 * Note: The message queue must be initialized before this call, else
 * the return value is meaningless 
 * @param m Pointer to the message queue
 * @return Number of messages in the queue */
mqind_t msgQ_count(/*@notnull@*/ /*@shared@*/ msgQ_t const *m);

/** Post a message to the queue.
 *
 * Calling Context: 
 *  -# After msgQ_init() of m (There is no check to ensure this). AND
 *    -# Before os_start().
 *    -# From within a task.
 *    -# From an ISR.
 *
 * In the current implementation, if the queue is full, an error is
 * returned.  The task is not allowed to block here.  This may be
 * changed in the future.
 * @param m  Pointer to message queue
 * @param tx_value  The value to be added to the queue.
 * @return {\ref SUCCESS, 
 *          \ref ERR_FULL}  */
int8_t msgQ_send(/*@notnull@*/ /*@shared@*/ msgQ_t *m, 
		 /*@shared@*/ osptr_t tx_value);
/*lint -ecall(740,msgQ_send) If dummy is passed directly to msgQ_send
 *   with casting, this is OK. */


/** Wait for message.
 *
 * Calling Context: 
 *  -# After msgQ_init() of m (There is no check to ensure this). AND
 *    -# Before os_start() (error if blocking needed).
 *    -# From within a task.
 *    -# From an ISR (error if blocking needed).
 *
 * @param m Pointer to message queue
 * @param timeout  Timeout. This can be 0 for infinite timeout.
 * @param options [\ref O_NONBLOCKING | \ref O_RELATIVE_TIME ].
 * @param [out] rx_value  Pointer to memory where the message should
 *                        be stored.
 * @return {\ref SUCCESS, 
 *          \ref ERR_WOULDBLOCK_ISR, 
 *          \ref ERR_WOULDBLOCK_MUTEX,
 *          \ref ERR_TIMEOUT, 
 *          \ref ERR_RESUMED}.
*/
int8_t msgQ_recv(/*@notnull@*/ /*@shared@*/ msgQ_t *m, trtime_t const *timeout, uint8_t options, 
		 /*@special@*/ osptr_t *rx_value) 
	/*@defines *rx_value@*/
	/*@modifies *m, *rx_value@*/ 	;
/*lint -ecall(740,msgQ_recv) If dummy is passed directly to msgQ_recv
 *   with casting, this is OK. */


/** @} */
#endif   /* TIROS_ENABLE_MSGQ */







#if (TIROS_ENABLE_EFLAG == 1)
/** @defgroup os_eflag Event Flags
 *  Event flags allow tasks to wait for a specific combination of
 *  events.  An event flag is a bitmask.  Waiting tasks can specify a
 *  subset of the bitmask as events of interest.  They can either wait
 *  for ALL of the events to occur or ANY of the events to occur. 
 *
 * NOTE: MUST ALWAYS INITIALIZE BEFORE USE.
 * \code

 * eflag_t notification;   // Previously initialized
 * #define ALERT0  0x01
 * #define ALERT1  0x02
 * void task1(void *dummy)
 * {
 *   int8_t rc;
 *   while(1) {
 *       rc = eflag_wait( &notification, ALERT0, 0, 0, );
 *       if (rc == SUCCESS) {
 *          do_something();
 *       }
 *   }
 * }
 * void task2(void *dummy)
 * {
 *   int8_t rc;
 *   while(1) {
 *       // Trigger event
 *       rc = eflag_set(&notification, ALERT0|ALERT1, O_EFLAG_TRIGGER); 
 *       do_other_stuff();
 *   }
 * }
 *\endcode
 *
 * @{ */

/** Initialize an event flag. *
 *
 * Calling Context: 
 *  -# Before os_start().
 *  -# From within a task.
 *  -# From an ISR.
 *
 *  @param ef Pointer to the event flag.
 *  @param initval Initial value for the event flag */
void eflag_init(/*@notnull@*/ /*@shared@*/ eflag_t *ef, flag_t initval);

/** Set an event flag. 
 *
 * Calling Context: 
 *  -# After eflag_init() of ef (There is no check to ensure this). AND
 *    -# Before os_start().
 *    -# From within a task.
 *    -# From an ISR.
 *
 * @param ef Pointer to the event flag.
 * @param setbits The new bitvalues to be set or cleared.
 * @param options [\ref O_EFLAG_CLEAR, \ref O_EFLAG_TRIGGER]
 *\verbatim
   O_EFLAG_CLEAR   : Clear the specified bits.  Default is to set them. 
   O_EFLAG_TRIGGER : Just pulse the values in the prescribed
                     fashion. Don't set them permanently.  If any of the 
                     flag values were set before the trigger, they stay
                     set after the call.
 \endverbatim
 * @return {\ref SUCCESS,  
 *          \ref ERR_FAILED}
 **/
int8_t eflag_set(/*@notnull@*/ /*@shared@*/ eflag_t *ef, flag_t setbits, uint8_t options);

/** Peek at the value of an event flag.
 * This can be used for polling.
 *
 * Calling Context: 
 *  -# After eflag_init() of ef (There is no check to ensure this). AND
 *    -# Before os_start().
 *    -# From within a task.
 *    -# From an ISR.
 *
 * @param ef Pointer to the flag.
 * @return Current setting for the event flag */
flag_t eflag_get(/*@notnull@*/ eflag_t const *ef);

/** Wait for an event flag.
 *
 * A blocking call from an ISR will result in an error. So, there is
 * usually no need to call this from an ISR. eflag_get may be
 * preferable. 
 *
 * Calling Context: 
 *  -# After eflag_init() of (There is no check to ensure this). AND
 *    -# From within a task.
 *    -# Before os_start() (error if blocking needed).
 *    -# From an ISR (error if blocking needed).
 *
 * @param     ef Pointer to the event flag.
 * @param     checkbits  Bits to be checked.
 * @param [in] timeout  Timeout. This can be 0 for infinite timeout.
 * @param options [\ref O_NONBLOCKING | \ref O_RELATIVE_TIME | 
 *                 \ref O_EFLAG_AND | \ref O_EFLAG_OR ].
 * @return {\ref SUCCESS, 
 *          \ref ERR_WOULDBLOCK_ISR, 
 *          \ref ERR_WOULDBLOCK_MUTEX,
 *          \ref ERR_TIMEOUT, 
 *          \ref ERR_RESUMED}
 */
int8_t eflag_wait(/*@notnull@*/ /*@shared@*/ eflag_t *ef, 
		  flag_t checkbits, trtime_t const *timeout, 
		  uint8_t options );
/** @}  End Eflags */
#endif   /* TIROS_ENABLE_EFLAG */



/** @defgroup os_advanced Advanced Features and Debugging
 * TiROS has API calls for debugging and per-task customization.
 * 
 * <H4> Notification of context switching </H4>
 * Using the TIROS_USER_CTXT_UPCALL feature, a user supplied function, 
 * user_ctxt_upcall(), can be kept informed of context switching.
 * This can be used in creative ways to implement per-task hardware
 * customization.  For example, the upcall can be used to save the
 * low-power state of the current task and set the low-power state of
 * the next task.  This will result in per-task power control.
 *
 * <H4> Debugging with TiROS </H4>
 * Two types of debugging information can be retrieved from TiROS.
 * <OL>
 * <LI> One
 * is a simple text based error log that is activated by setting
 * TIROS_DEBUG_LEVEL higher than 0.  Output messages depend on the
 * debug level.
     \verbatim
      0 - No debugging messages.
      1 - Critical error messages.
      2 - Adds warning mesages.
      3 - Adds informational messages.
      4 - Adds trace messages.
      \endverbatim
 * The debug output from TiROS gets channeled to the putchar(int char)
 * function. To get debugging information, ensure that putchar() is
 * properly implemented.  By implementing putchar() appropriately, the
 * output can be directed to a serial port or to a file.
 * 
 * </LI>
 * <LI> Another method of debugging (and the most powerful) is to periodically capture the
 * internal state of TiROS.  This is done by a user task by calling
 * the osint_snapshot function. To enable this function, define
 * TIROSINT_DATA_DEBUG in the proj_config.h file, and include
 * tr_debug.h in your source file.  The osint_snapshot() function can be used to
 * capture the TiROS state into a memory buffer (no need for putchar()) which
 * can then be output as  desired.   An example of the use of this
 * form of debugging is provided as an example in os_examples/os_debug_example
 * </LI>
 * </OL>

 *
 * @{ */


#ifdef TIROS_USER_CTXT_UPCALL
/** User context upcall when the scheduler schedules tasks.
 * This upcall can be used to inform the user program of task
 * rescheduling.  This function is only available if TIROS_USER_CTXT_UPCALL
 * is defined.  This function is not implemented by the OS.  It should be
 * implemented by the user and TIROS_USER_CTXT_UPCALL should be defined in
 * the proj_config.h file if this feature 
 * @param curr_task  The task id of the task being switched out.
 * @param next_task  The next task that is going to run.
 */
void user_ctxt_upcall(tid_t curr_task, tid_t next_task);
#endif

/** @} */




/** @defgroup ret_codes Return Codes.
 *
 * The common return codes and their descriptions are given
 * below. Error return codes have a major and minor number.  The major
 * number provides the error family.  The minor number gives more detail.
 * @{ */

/** Extract the major error code out of the return value */
#define ERR_MAJOR(x) ((x) & (~7) )
/** Extract the minor error code out of the return value */
#define ERR_MINOR(x) ((x) & 7)


/** Notation for an invalid task */
#define ILLEGAL_ELEM  ((tid_t) ~0)


/** Return code success. */                  
#define SUCCESS			0       

/** Minor error code indicating that error occurence was due to
 *  invocation from an ISR or from main code before os_start() */
#define EMINOR_ISR		0x01

/** Minor error code indicating that action would violate rules to
 *  prevent priority inversion */
#define EMINOR_PRIO_RULE	0x02




/** Mutex locking error */
#define ERR_LOCK		-8

/** Mutex locking error: locking from ISR or before os_start() */
#define ERR_LOCK_ISR		(ERR_LOCK | EMINOR_ISR)

/** Mutex locking error: denied by priority ceiling  */
#define ERR_LOCK_PRIO_CEIL	(ERR_LOCK | EMINOR_PRIO_RULE)




/** Operation would cause blocking, option O_NONBLOCKING  specified */
#define ERR_WOULDBLOCK		-16

/** This has been called from an ISR or before os_start() 
 *    but would result in blocking */
#define ERR_WOULDBLOCK_ISR	(ERR_WOULDBLOCK | EMINOR_ISR)

/** This call would block and is denied because a Mutex is being held.
 *  The current combination of synchronization primitives would
 *     result in the unwanted blocking of a mutex.  */
#define ERR_WOULDBLOCK_MUTEX	(ERR_WOULDBLOCK | EMINOR_PRIO_RULE)





/** A message queue is full or a counting semaphore is maxed out */
#define ERR_FULL		-24



/** Failure: Not the owner of the specified mutex, or the mutex is not
 * locked.*/
#define ERR_NOTOWNER		-32



/** A timeout has occured. */
#define ERR_TIMEOUT		-40

/** Task was resumed while sleeping or waiting for a lock */
#define ERR_RESUMED		-48


/** Specified task does not exist. */
#define ERR_NOSUCHTASK		-56


/** The operation cannot be completed because a specified task
 *    is blocked. */
#define ERR_TASKBLOCKED		-64

/** The operation failed because the desired priority is in use */
#define ERR_PRIO_IN_USE		-72

/** Failure: reason unspecified. */
#define ERR_FAILED		-80


/** @} ret_codes */



#endif
